#ifndef WRSERVICE_SERVICE_H
#define WRSERVICE_SERVICE_H

#include <windows.h>
#include <memory>
#include "config.h"
#include "Log.h"

namespace wrservice
{

class Service
{
    LPWSTR                  name_;          // service name
    SERVICE_STATUS          status_;        // current service status
    SERVICE_STATUS_HANDLE   status_handle_; // service status handle of registered
                                            //  function SvcCtrlHandler
    HANDLE                  stop_event_;    // is needed to terminate the thread
                                            //  in which SvcMain is running
    bool                    is_running_;    // service running status
    std::auto_ptr<Log>      log_;           // service log

    static Service*         p_instance_;
    static bool             is_destroyed_;

    // create new object of class Service
    //  implementation : Meyers singleton
    static void Create ()
    {
        static Service obj;
        p_instance_ = &obj;
    }

    static void OnDeadReference ()
    {
        throw std::runtime_error ("Dead reference to Service detected");
    }

    Service ()
        : name_(L""),        is_running_(false),
          status_(),         status_handle_(),
          stop_event_(NULL), log_(new Log())
    {
        // set default status
        this->status_.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 
        this->status_.dwServiceSpecificExitCode = 0;
    }
    Service(const Service& svc);
    Service& operator=(const Service& svc);

    //void start_thread_ ();
    
public:
    static Service& instance ()
    {
        if (!p_instance_)
        {
            // dead reference check
            if (is_destroyed_)
                OnDeadReference();
            else // first call - initialization
                Create();
        }
        return *p_instance_;
    }
    
    virtual ~Service()
    {
        p_instance_ = 0;
        is_destroyed_ = true;
    }

    void update_status (
        __in DWORD dwCurrentState,
        __in DWORD dwWin32ExitCode,
        __in DWORD dwWaitHint
        );
    void config(service_config_t);
    void execute();

    bool                   get_state()         const { return is_running_; }
    LPWSTR                 get_name()          const { return name_; }
    Log&                   get_log()           const { return *log_; }
    HANDLE                 get_stop_event()    const { return stop_event_; }
    SERVICE_STATUS         get_status()        const { return status_; }
    SERVICE_STATUS_HANDLE  get_status_handle() const { return status_handle_; }
    
    void set_state (bool st)     { is_running_ = st; }
    void set_name  (LPWSTR name) { name_ = name; }
    void set_status(SERVICE_STATUS st)
    { 
        status_ = st;
        update_status (
            status_.dwCurrentState,
            status_.dwWin32ExitCode,
            status_.dwWaitHint );
    }
    void set_status_handle (SERVICE_STATUS_HANDLE h) 
        { status_handle_ = h; }
    void set_stop_event    (HANDLE h)
        { stop_event_ = h; }
};


void WINAPI service_start_thread ();
void WINAPI service_main (
    __in DWORD  dwArgc, 
    __in LPWSTR *lpszArgv
    );
void WINAPI service_main_init (
    __in DWORD  dwArgc, 
    __in LPWSTR *lpszArgv
    );
void WINAPI service_control_handler (
    __in DWORD  dwCtrl
    );
DWORD WINAPI service_execution_thread (
    __in LPDWORD param
    );

void service_config (Service& svc, LPCWSTR con);

} /* namespace wrservice */

#endif /* WRSERVICE_SERVICE_H */
